package com.liu.springmvc.servlet;

import com.liu.springmvc.adapter.HandlerAdapter;
import com.liu.springmvc.handler.HandlerExecutionChain;
import com.liu.springmvc.handler.HandlerMapping;
import com.liu.springmvc.view.ModelAndView;
import com.liu.springmvc.view.MyViewResolver;
import com.liu.springmvc.view.View;
import com.liu.springmvc.view.ViewResolver;
import org.springframework.context.ApplicationContext;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * @author LIU
 * @version 1.0
 * @description TODO
 * @date 2024/1/23 9:49
 */
public class LiuDispatcherServlet extends FrameworkServlet {
    // 请求映射器   维护url和处理器的路由关系
    private List<HandlerMapping> handlerMappings;
    // 请求适配器
    private List<HandlerAdapter> handlerAdapters;
    // 视图解析器
    private List<ViewResolver> viewResolvers;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp){

        try {
            doDispatch(req, resp);
        } catch (Exception e) {
            e.printStackTrace();

            HashMap<String, Object> model = new HashMap<>();
            model.put("detail","500 Exception");
            model.put("stackTrace", Arrays.toString( e.getStackTrace()));

            try {
                processDispatchResult(req,resp,new ModelAndView("500",model));
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }


    /**
     * 根据url委派给具体的调用方法
     * @param req
     * @param resp
     * @throws IOException
     */
    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {

        //1、根据URL 拿到对应的Handler
        HandlerExecutionChain mappedHandler = getHandler(req);
        if (mappedHandler == null) {
//            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            //重定向 /404 请求
            req.getRequestDispatcher("/404").forward(req,resp);
            return;
        }

        //2、根据handlerMapping拿到HandlerAdapter
        HandlerAdapter adapter = getHandlerAdapter(mappedHandler.getHandler());


        //3、根据HandlerAdapter拿到对应的ModelAndView
        Object result = adapter.handler(req, resp, mappedHandler.getHandler());

        if (result instanceof ModelAndView) {
            //4、根据ViewResolver找到对应View对象
            //通过View对象渲染页面，并返回
            processDispatchResult(req,resp,(ModelAndView) result);
        }else if (result != null) {
            // JSON输出流
            resp.getWriter().println(result);
        }
    }


    private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, ModelAndView mv) throws Exception {
        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(mv.getViewName());
            view.render(mv.getModel(),req,resp);
            return;
        }
    }

    private HandlerExecutionChain getHandler(HttpServletRequest res) {
        if (this.handlerMappings != null) {
            for (HandlerMapping mapping : this.handlerMappings) {
                HandlerExecutionChain handler = mapping.getHandler(res);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

    private HandlerAdapter getHandlerAdapter(Object handler) {
        if (this.handlerAdapters != null) {
            for (HandlerAdapter adapter : this.handlerAdapters) {
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }
        throw new NullPointerException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");

    }


    /**
     * 初始化springMVC九大组件
     */
    @Override
    protected void onRefresh(ApplicationContext context) {
        initHandlerMappings(context);       // 请求映射器
        initHandlerAdapters(context);       // 请求适配器
        initViewResolvers(context);       // 视图解析器

//        initMultipartResolver(context);   //文件上传处理器
//        initHandlerExceptionResolvers(context);  // 异常处理器
//        initLocaleResolver(context);
//        initThemeResolver(context);
//        initRequestToViewNameTranslator(context);

//        initFlashMapManager(context);
    }

    /**
     * 视图解析器
     * @param context
     */
    private void initViewResolvers(ApplicationContext context) {
        //src/main/resources/layouts
        String templateRootPath = this.getClass().getClassLoader().getResource("layouts").getFile();

//        File file = new File(templateRootPath);
//        for (File listFile : file.listFiles()) {
//
//        }

        ArrayList<ViewResolver> list = new ArrayList<>();
        list.add(new MyViewResolver(templateRootPath));
        this.viewResolvers = list;
    }

    /**
     *  初始化适配器
     */
    private void initHandlerAdapters(ApplicationContext context) {
        this.handlerMappings = new ArrayList<>(context.getBeansOfType(HandlerMapping.class).values());
    }
    /**
     *  初始化映射器
     */
    private void initHandlerMappings(ApplicationContext context) {
        this.handlerAdapters = new ArrayList<>(context.getBeansOfType(HandlerAdapter.class).values());
    }
}
